﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Oracle.ManagedDataAccess.Client;
using WFL.Data.Oracle;
using WFL.IoCUnity;

namespace WFL.RBAC.Oracle
{
    public class UserDAL : BaseDAL, IUser
    {

        #region 接口方法

        public void BindRole(int userId, int roleId)
        {
            OnBindRole(userId, roleId);
        }

        public void UnbindRole(int userId, int roleId)
        {
            OnUnbindRole(userId, roleId);
        }

        public void UnbindRole(int userId)
        {
            OnUnbindRole(userId);
        }

        public IList<Role> GetRoleList(int userId)
        {
            return OnGetRoleList(userId);
        }

        public IList<T> GetLimitResourceList<T>(int userId, int resourceId, int operations) where T : new()
        {
            return OnGetLimitResourceList<T>(userId, resourceId, operations);
        }

        #endregion

        #region 虚方法

        protected virtual void OnBindRole(int userId, int roleId)
        {
            string sql = @"insert into UserRoles(userId,roleId)values(:UserId,:RoleId)";
            OracleParameter[] parameters = new OracleParameter[]
            {
                new OracleParameter("UserId",userId),
                new OracleParameter("RoleId",roleId),
            };
            ExecuteNonQuery(sql, parameters);
        }

        protected virtual void OnUnbindRole(int userId, int roleId)
        {
            string sql = @"delete from UserRoles where userId=:UserId and roleId=:RoleId";
            OracleParameter[] parameters = new OracleParameter[]
            {
                new OracleParameter("UserId",userId),
                new OracleParameter("RoleId",roleId),
            };
            ExecuteNonQuery(sql, parameters);
        }

        protected virtual void OnUnbindRole(int userId)
        {
            string sql = @"delete from UserRoles where userId=:UserId";
            OracleParameter[] parameters = new OracleParameter[]
            {
                new OracleParameter("UserId",userId),
            };
            ExecuteNonQuery(sql, parameters);
        }

        protected virtual IList<Role> OnGetRoleList(int userId)
        {
            string sql = @"select r.id,r.name from role r join userRoles ur on ur.roleId=r.id where ur.userId=:UserId";
            OracleParameter[] parameters = new OracleParameter[]
            {
                new OracleParameter("UserId",userId),
            };
            OracleDataReaderExtension readerEx = ExecuteReaderExtension(sql, parameters);
            try
            {
                if (!readerEx.Reader.Read())
                {
                    return null;
                }
                IList<Role> list = new List<Role>();
                do
                {
                    Role item = new Role();
                    item.Id = Convert.ToInt32(readerEx.Reader[0]);
                    item.Name = readerEx.Reader.GetString(1);
                    list.Add(item);
                } while (readerEx.Reader.Read());
                return list;
            }
            finally
            {
                readerEx.Close();
            }
        }

        protected virtual IList<T> OnGetLimitResourceList<T>(int userId, int resourceId, int operations) where T : new()
        {
            StringBuilder sqlBd = new StringBuilder();
            sqlBd.Append("select ");
            IList<string> fields = Orm.GetFields(typeof(T));
            sqlBd.Append("ri.");
            sqlBd.Append(fields[0]);
            for (int i = 1; i < fields.Count; i++)
            {
                sqlBd.Append(",ri.");
                sqlBd.Append(fields[i]);
            }
            sqlBd.Append(" from Permissions p join ");
            IResource resourceDAL = UnityUtility.Resolve<IResource>();
            Resource resource = resourceDAL.Get(resourceId);
            if (resource == null)
            {
                throw new ArgumentException(string.Format("无法找到资源定义：{0}", resourceId));
            }
            //获取资源限定列表
            IList<ResourceLimit> resourceLimits = resourceDAL.GetResourceLimitList(resource.Id);
            if (resourceLimits == null || resourceLimits.Count > 0)
            {
                throw new Exception(string.Format("资源\"{0}\"无法通过类型\"{1}\"限定", resourceId, typeof(T).AssemblyQualifiedName));
            }

            Resource lastResource = resourceDAL.Get(resourceLimits[0].ResourceId);
            Type lastResourceType = Type.GetType(lastResource.TypeName);
            sqlBd.Append(Orm.GetTableName(lastResourceType));
            sqlBd.Append("r0 on p.LimitResourceItemId=r0.");
            sqlBd.Append(Orm.GetField(lastResourceType, resourceLimits[0].ResourcePropertyName));
            for (int i = 1; i < resourceLimits.Count; i++)
            {
                //获取当前限定资源链
                //IList<ResourceLimit> chain=resourceDAL.GetResourceLimitChain(resource.Id,)
                ResourceLimit item = resourceLimits[i];
                Resource limitResource = resourceDAL.Get(item.LimitId);
                Type limitResourceType = Type.GetType(limitResource.TypeName);
                sqlBd.Append(string.Format(" join {0} r{1} on r{2}.{3}=r{1}.{4}"
                    , Orm.GetTableName(limitResourceType)
                    , limitResource.Id == resource.Id ? "i" : i.ToString()
                    , (i - 1).ToString()
                    , item.ResourcePropertyName
                    , Orm.GetField(limitResourceType, item.LimitPropertyName)));
                lastResource = limitResource;
                lastResourceType = limitResourceType;
            }

            throw new NotImplementedException();
        }

        #endregion

    }
}
